<?php
namespace TbfCrypt;

/**
 * map a num to an encrypt num in the some range
 * with correct parameter,
 *     the encrypt num will not repeat in that range,
 *     the encrypt num will look like random.
 */
class LcgIndexGenerator {
    /** @var int start of the range(included) */
    protected $s;
    /** @var  int length of the range */
    protected $m;
    /** @var  int parameter a */
    protected $a;
    /** @var  int parameter c */
    protected $c;
    function __construct($s,$m,$a,$c){
        $this->s = $s;
        $this->m = $m;
        $this->a = $a;
        $this->c = $c;
    }

    /**
     * map a num to an encrypt num in the some range
     * it will not check range of index
     * @param $index
     * @return int
     */
    function generate($index){
        return $this->s + ($index * $this->a + $this->c ) % $this->m;
    }
    /**
     * map a num to an encrypt num in the some range
     * it will throw exception if index of range...
     * @param $index
     * @return int
     * @throws \Exception
     */
    function checkAndGenerate($index){
        if ($index >= ($this->s+$this->m)){
            throw new \Exception(
                sprintf('LcgIndexGenerator index out of range ,should less than %d,get %d.',
                    ($this->s+$this->m),
                    $index
                ));
        }
        if ($index < $this->s){
            throw new \Exception(
                sprintf('LcgIndexGenerator index out of range ,should greater or equal than %d,get %d.',
                    $this->s,
                    $index
                ));
        }
        return $this->s + ($index * $this->a + $this->c ) % $this->m;
    }
    /**
     * new object from start and end num.
     * include start num, not include end num.
     * @param $s
     * @param $e
     * @param $a
     * @param $c
     * @return LcgIndexGenerator
     */
    public static function newByStartEnd($s,$e,$a,$c){
        return new LcgIndexGenerator($s,$e-$s,$a,$c);
    }
}